#include<iostream>
#include<cstdlib>
#include<string.h>

class myhashmap
{
private:
    class Node
    {
    public:
        char* data;
        Node* next;
        int num;
        Node(){data = NULL; next = NULL; num = 0;}
        Node(char* _data){data = _data; next = NULL; num = 0;};
        ~Node(){};
    };

    Node* table[3000];
    struct wordandnum
    {
        int num;
        char* data;
    };
    struct wordandnum word[20];
    
public:
    myhashmap();
    ~myhashmap();
    void deletenode(Node* _data);
    int myhash(char* _data);
    void readaword(char* _data);
    void insertword(Node* _p);
    void print_most20();
};

int isabc(char _c)
{
    if(_c - 'a' >= 0 && _c - 'a' <= 25)
        return 1;
    else if(_c - 'A' >= 0 && _c - 'A' <= 25)
        return 1;
    else
        return 0;
}

myhashmap::myhashmap()
{
    
    for(int i = 0; i < 3000; i++)
    {
        table[i] = new Node();
    }
    
   //table[3000] = { NULL };
    for(int i = 0; i < 20; i++)
    {
        word[i].num = 0;
        word[i].data = NULL;
    }
};

void myhashmap::deletenode(Node* _data)
{
    if(_data->next != NULL)
    {
        deletenode(_data->next);
    }
    delete _data;
}
myhashmap::~myhashmap()
{
    for(int i = 0; i < 3000; i++)
    {
        deletenode(table[i]);
    }
};

int myhashmap::myhash(char* _data)
{
    int index = 0;
    char c;
    for(; *_data != '\0'; _data++)
    {
        if(*_data - 'A' >= 0 && *_data - 'A' <= 25)
            c = *_data + 32;
        else
            c = *_data;
        index += c;
    }
    return index;
};

void myhashmap::readaword(char *_data)
{
    int k = myhash(_data);
    if(table[k]->data == NULL)
    {
        table[k]->num++;
        table[k] = new Node(_data);
        if(table[k]->num > word[19].num) insertword(table[k]);
    }
    else
    {
        Node* p = table[k];
        while(strcmp(_data, p->data) != 0 && p->next != NULL)
        {
            p = p->next;
        }
        if(strcmp(_data, p->data) == 0) p->num++;
        else
        {
            p->next = new Node(_data);
            p = p->next;
            p->num++;
        }
        if(p->num > word[19].num) insertword(p);
    }
}

void myhashmap::insertword(Node* _p)
{
    int flag = 0;
    for(int i = 0; i < 20; i++)
    {
        if(word[i].data != NULL)
        {
        if(strcmp(word[i].data, _p->data) == 0)
        {
            flag = 1;
            word[i].num++;
            for(int j = i; j > 0; j--)
            {
                if(word[j].num > word[j-1].num)
                {
                    wordandnum tmp = word[j];
                    word[j] = word[j-1];
                    word[j-1] = tmp;
                }
            }
        }
        }
    }
    if(flag == 0)
    {
    word[19].data = _p->data;
    word[19].num = _p->num;
    for(int i = 19; i > 0; i--)
    {
        if(word[i].num > word[i-1].num)
        {
            wordandnum tmp = word[i];
            word[i] = word[i-1];
            word[i-1] = tmp;
        }
        else
        {
            break;
        }
    }
    }
}

void myhashmap::print_most20()
{
    for(int i = 0; i < 20; i++)
    {
        std::cout << word[i].data << ":   " << word[i].num << std::endl;
    }
}
